Skip to content

Revert claude-review to the pull_request trigger - #89

Merged
d-morrison merged 1 commit into
mainfrom
fix/claude-review-pull-request-trigger
Aug 1, 2026
Merged

Revert claude-review to the pull_request trigger#89
d-morrison merged 1 commit into
mainfrom
fix/claude-review-pull-request-trigger

Conversation

@d-morrison

@d-morrison d-morrison commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes #88.

What was broken

Every Claude Code Review run has failed since #83 merged, at the token-exchange step:

OIDC token successfully obtained
Exchanging OIDC token for app token...
App token exchange failed: 401 Unauthorized - Invalid OIDC token

Claude never got as far as reading a diff.
The most recent instance is
run 30677231096 on #76.

Why

#83 switched the trigger to pull_request_target.
Anthropic's exchange endpoint rejects OIDC tokens minted for that event.
The action's code supports it; the server side does not.
Open upstream since 2025-12-02 as
anthropics/claude-code-action#713,
whose stated workaround is to use pull_request.

Five of five pull_request_target runs failed this way, and no pull_request run
ever has --- the two runs immediately before the switch both succeeded.
The full before/after table is in #88.

What this changes

  • Trigger back to pull_request, with a comment naming the upstream issue
    so the switch does not get re-applied.
  • Drops ref: ${{ github.event.pull_request.head.sha }}.
    The action's security doc
    warns against checking an untrusted ref into the workspace root of a job
    holding the base repository's secrets.
  • Restores pull-requests: read.
    The action posts with its own app token, so the workflow token does not need write.

The result is byte-identical to the last version that produced successful reviews,
plus the comment.

Fork PRs

Corrected. This section originally said no fork PR had ever been opened against
this repo. That is false: #77
(imelainew/ucd-serg.github.io) has been open since 2026-06-30. I read main in the
branch column as a same-repo branch without checking head.repo.fork.

The revert is unchanged, but the reason has to be the true one.

A fork PR gets no Claude review under either configuration:

  • Under pull_request, GitHub withholds the secret and the OIDC token from a fork PR
    whatever the permissions: block says.
    Run 30663424918
    on Add Elaine Wang profile to team page #77 logs "claude_code_oauth_token": "" and then fails to get an OIDC token ---
    under an error message that wrongly blames a missing id-token: write.
  • Under pull_request_target, the exchange 401s for every PR, forks included.
    And a working exchange would still leave the action refusing to run for a contributor
    without write access unless allowed_non_write_users is set, which upstream documents
    as a significant security risk.

So pull_request_target was not buying fork coverage at the cost of everything else.
It was reviewing nothing. This revert restores reviews for the three same-repo PRs and
leaves #77 exactly where it already was, tracked as
#90.

#84 remains separate --- Copilot-authored PRs fail the same step with
User does not have write access on this repository, a non-collaborator triggering
actor on a same-repo branch.

Verification

Corrected after the first run. This section originally said a green claude-review
on this PR would be the fix testing itself. That is wrong, and the reason is worth stating,
since the check does go green.

Because this PR edits the review workflow, the head version no longer matches the copy on
the default branch, so the exchange endpoint returns a workflow-validation error and the
action skips, exiting 0. The green check is a skip, not a review.

What the two runs do establish is where each one stopped, which is the thing in question:

Run Trigger Stopped at
30680266785 pull_request workflow validation --- the OIDC token was accepted
30680266779 pull_request_target 401 Invalid OIDC token --- rejected outright

Same repo, same secret, same minute, one variable. The red check is main's current
workflow reviewing this PR; it cannot go green before merge and stops firing afterward.
main is unprotected, so nothing is blocked.

A real end-to-end review is only observable on the next PR after this one merges.

Anthropic's token-exchange endpoint rejects OIDC tokens minted for
pull_request_target events, so every review run since #83 failed with
"401 Unauthorized - Invalid OIDC token" before Claude started. Tracked
upstream as anthropics/claude-code-action#713, still open.

Also drops the untrusted head-ref checkout #83 added, which the action's
own security doc warns against for pull_request_target, and restores
pull-requests: read.

Closes #88

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HMmB6db4xpbuqcqaQKArZb
@d-morrison

Copy link
Copy Markdown
Member Author

Working on this --- paws off until I'm done.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1-2-g6ad689f
Preview removed because the pull request was closed.
2026-08-01 02:49 UTC

@d-morrison

Copy link
Copy Markdown
Member Author

Both claude-review results are expected, and neither is a review

Run Trigger Outcome
30680266785 pull_request (this branch's workflow) pass, 11s
30680266779 pull_request_target (main's workflow) fail, 25s

Read the logs rather than the colors --- the green one is a skip, not a review:

Skipping action due to workflow validation: Workflow validation failed.
The workflow file must exist and have identical content to the version on
the repository's default branch.

That is the documented behavior for a PR that edits the review workflow, and the action exits 0 on it.

The point is where each run stopped. The pull_request run's OIDC token was accepted and it got as far as workflow validation; the pull_request_target run, in the same repo, in the same minute, on the same secret, was rejected outright at 401 Invalid OIDC token. That is the cleanest available demonstration of the cause, since the only variable between them is the trigger event.

The red check is main's current workflow reviewing this PR. It cannot go green before merge, and it stops firing once this lands. main is unprotected, so it does not block.

No external verdict is obtainable at this head, so I have requested Copilot review and will self-review in the meantime.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Restores the Claude Code Review GitHub Actions workflow to use the pull_request trigger to address consistent OIDC→App-token exchange failures observed under pull_request_target, and tightens the workflow’s checkout and permissions accordingly.

Changes:

  • Switch workflow trigger from pull_request_target back to pull_request, with an inline comment referencing the upstream Anthropic issue.
  • Remove checkout of the PR head SHA to avoid checking out an untrusted ref into a secrets-bearing workspace.
  • Reduce pull-requests permission from write to read (the action posts using its own app token).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@d-morrison

Copy link
Copy Markdown
Member Author

Ready for merge

Copilot reviewed the current head (4160c10) at 02:36Z and returned no findings --- its overview describes all three changes correctly. Zero inline threads, no CHANGES_REQUESTED.

Checks:

Check Result
Spellcheck pass
build-deploy pass
lint-project pass
CodeFactor pass
claude-review (pull_request) pass --- but a skip, not a review, per the workflow-validation note above
claude-review (pull_request_target) fail

That last one is red by design, not oversight: it is main's current broken workflow reviewing the PR that fixes it, and no change to this branch can turn it green. It stops firing the moment this merges. main is unprotected, so it does not block.

claude-review did not produce a verdict at this head for the skip reason, so the clean call rests on Copilot's review alone. A genuine end-to-end review is first observable on the next PR opened after this merges --- worth watching, since that is the real confirmation.

Not merging --- that is yours to call.

@d-morrison
d-morrison merged commit 3671f14 into main Aug 1, 2026
6 of 7 checks passed
@d-morrison
d-morrison deleted the fix/claude-review-pull-request-trigger branch August 1, 2026 02:48
@d-morrison

Copy link
Copy Markdown
Member Author

Correction: this repo does have a fork PR

The body's "Fork PRs" section claimed none had ever been opened here. That is false --- #77 (imelainew/ucd-serg.github.io) has been open since 2026-06-30. I read main in the branch column as a same-repo branch instead of checking head.repo.fork. The section is rewritten in place and marked as corrected, since the original is what Copilot's review read.

A second claim in #88 was wrong the same way: I described run 30663424918 as "missing id-token: write". That is #77's run, the workflow does grant it, and GitHub withholds it from fork PRs regardless. The run's own error text guesses at the misconfiguration I then repeated.

The revert still stands, on a corrected argument. pull_request_target was not trading fork coverage for anything --- the exchange 401s on every PR, forks included, and a working exchange would still refuse an outside contributor without allowed_non_write_users. Fork PRs are unreviewed today and stay unreviewed after this merges, which is now tracked as #90 rather than dismissed in a PR body.

Nothing in the diff changes. Re-requesting review since the description Copilot reviewed no longer matches.

@d-morrison
d-morrison requested a review from Copilot August 1, 2026 02:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@d-morrison

Copy link
Copy Markdown
Member Author

Copilot re-reviewed at 02:52Z against the corrected description: "reviewed 1 out of 1 changed files and generated no new comments." Two clean reviews now, zero inline comments, and the diff is unchanged from the first one. Still ready; still yours to merge.

@d-morrison

Copy link
Copy Markdown
Member Author

Correction, post-merge: one claim in this PR was false, and #91 is fixing its consequence.

I wrote that reducing pull-requests from write to read was safe because "the action posts with its own app token, so the workflow token does not need write." That is wrong. The app token covers the action's own bookkeeping; the review is posted by Claude's tool calls under GITHUB_TOKEN, so read denies them --- permission_denials_count: 8 in run 30681158599 on #87, with the check still green.

I also called this diff "byte-identical to the last version that produced successful reviews." Byte-identical, yes. Producing reviews, no: claude has never posted a review comment on this repo. #78, #79, #80, and #86 all ran green with zero, and git log -L shows pull-requests: read present since the workflow's first commit.

So the trigger fix here was right and the permissions change rode along on an untested premise. Both facts held at once and the second was invisible, because a green check is what a silently-dropped review looks like --- the same reading failure this PR's own description warns about for the workflow-validation skip, one line lower in the same file.

Fixed forward in #91 rather than by reopening this. Evidence posted there.

d-morrison pushed a commit to imelainew/ucd-serg.github.io that referenced this pull request Aug 1, 2026
pull-requests was narrowed to read in UCD-SERG#89 while fixing the OIDC
failure, but that also silently disables posting reviews on same-repo
PRs: the job runs and succeeds, but every write attempt is denied
(confirmed via permission_denials_count in the job log) and no review
ever appears. write is safe to restore here: this workflow uses the
pull_request trigger (not pull_request_target), and GitHub always
forces a read-only GITHUB_TOKEN for fork PRs regardless of what
permissions: declares, so fork PRs stay read-only either way.
d-morrison pushed a commit to imelainew/ucd-serg.github.io that referenced this pull request Aug 1, 2026
claude-code-review.yml can't work for fork PRs: pull_request events
from forks never receive an OIDC token at all (GitHub never sets
ACTIONS_ID_TOKEN_REQUEST_URL for them, regardless of id-token: write -
confirmed on PR UCD-SERG#77, run 30686460528/job/91333167166), and switching to
pull_request_target doesn't help either since Anthropic's token-exchange
endpoint rejects OIDC tokens minted under that event (UCD-SERG#89,
anthropics/claude-code-action#713). issue_comment is subject to neither
restriction. Add a workflow, gated to OWNER/MEMBER/COLLABORATOR
commenters, that a maintainer can trigger with "@claude review" on any
PR - fork or not - to get the same review claude-code-review.yml gives
same-repo PRs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

claude-review fails on every PR: pull_request_target breaks the OIDC token exchange

2 participants